package com.cjack.frenchexcel.service;

import com.cjack.frenchexcel.config.ErrorCodeDefine;
import com.cjack.frenchexcel.dao.*;
import com.cjack.frenchexcel.exception.BankCardNotExsitException;
import com.cjack.frenchexcel.exception.CommonException;
import com.cjack.frenchexcel.exception.ConsumerImportRepeatException;
import com.cjack.frenchexcel.model.AdminUserModel;
import com.cjack.frenchexcel.model.ConsumerRecordModel;
import com.cjack.frenchexcel.service.consumer.MooncardConsumer;
import com.cjack.frenchexcel.table.*;
import com.cjack.frenchexcel.util.*;
import com.sargeraswang.util.ExcelUtil.ExcelLogs;
import com.sargeraswang.util.ExcelUtil.ExcelUtil;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class MoonCardService {

    private final static Logger LOG = LogManager.getLogger( MoonCardService.class);
    @Value("${file.upload.baseServerDir}")
    String baseServerDir;
    @Value("${file.upload.baseClientDir}")
    String baseClientDir;
    @Value("${file.upload.spelitor}")
    String spelitor;

    @Autowired
    MooncardConsumer mooncardConsumer;
    @Autowired
    ConsumerRecordService consumerRecordService;
    @Autowired
    RechargeRecordService rechargeRecordService;
    @Autowired
    UserAdminService userAdminService;
    @Autowired
    MooncardDao mooncardDao;
    @Autowired
    UserAdminDao userAdminDao;
    @Autowired
    private SystemparamDao systemparamDao;
    @Autowired
    private ConsumerRecordDao consumerRecordDao;
    @Autowired
    private MooncardCardDao mooncardCardDao;
    @Autowired
    private RechargeRecordDao rechargeRecordDao;
    @Autowired
    private DataSummaryService dataSummaryService;

    //根据每个员工的user_profile_id去mooncard平台查询今天的交易记录，保存到消费记录表
    public void handleExpenses( String startTime, String endTime){
        JSONArray expenses = mooncardConsumer.expenses( startTime, endTime);
        if( expenses != null && expenses.size() > 0){
            for( int i = 0 ; i < expenses.size() ; i ++){
                JSONObject expense = expenses.getJSONObject( i);
                JSONObject source = expense.getJSONObject( "source");
                AdminUserTable user = findByBankCard( source.getString( "token"));
                //判断数据是否已经存在
                MooncardTable table = mooncardDao.findByOrderId( expense.getString( "id"));
                if( table == null){
                    table = new MooncardTable();
                }
                table.setCarteIdentifiant( source.getString( "token"));
                table.setTransactionLink( source.getString( "transaction_link"));
                table.setDateDeDepense( expense.getString( "created_at"));
                table.setMontantEnDevise( expense.getString( "amount"));
                DecimalFormat df = new DecimalFormat("#.00");
                table.setMontantTTC( df.format( Double.valueOf( expense.getString( "amount"))));
                table.setOrderId( expense.getString( "id"));//保存mooncard平台的交易记录id，后续通过此字段去重
                table.setSourceFrom( "MOONCARD_AUTO");
                table.setCheckResAccount( 0);
                if( user == null){
                    table.setCollaborateur( "NOT_FOUND_USER");
                    table.setImportUserId( 2l);
                }else{
                    table.setCollaborateur( user.getJobNumber());
                    table.setImportUserId( user.getId());
                }
                mooncardDao.save( table);
            }
        }
    }

    //根据每个员工的account_id去mooncard平台查询今天的交易记录，通过transaction_link找到之前expense返回的交易记录，校验交易状态是否成功
    public void checkByAccountMovements( String startTime, String endTime){
        //startTime = "2020-03-01T00:00:00.845Z";
        JSONArray accountMoveMents = mooncardConsumer.account_movements( startTime, endTime);
        if( accountMoveMents != null && accountMoveMents.size() > 0){
            List<MooncardTable> noCheckDatas = mooncardDao.findByCheckResAccount();
            for( MooncardTable noCheckData : noCheckDatas){
                boolean flag = false;//校验结果
                JSONObject accountMoveMent = null;
                for( int i = 0 ; i < accountMoveMents.size() ; i ++){
                    accountMoveMent = accountMoveMents.getJSONObject( i);
                    if( accountMoveMent.getString( "transaction_link").equals( noCheckData.getTransactionLink())){
                        flag = true;
                        break;
                    }
                }
                //校验成功，将状态修改为-1
                if( flag){
                    noCheckData.setCheckResAccount( -1);
                    String fournisseur = handleDescription( accountMoveMent.getString( "description"));
                    //description字段的后半截是mooncard记录的供货商信息，保存到数据库
                    noCheckData.setFournisseur( fournisseur);
                    //这个字段也要同时更新到 消费记录表
                    List<ConsumerRecordTable> consumerRecordTables = consumerRecordDao.getByOtherIdAndSourceFrom( noCheckData.getId(), "MOONCARD_AUTO");
                    if( consumerRecordTables != null && consumerRecordTables.size() > 0){
                        for( ConsumerRecordTable consumerRecordTable : consumerRecordTables){
                            consumerRecordTable.setFournisseur( fournisseur);
                            consumerRecordTable.setCheckResAccount( -1);
                            consumerRecordDao.save( consumerRecordTable);
                        }
                    }
                }else{//校验失败，校验次数+1
                    noCheckData.setCheckResAccount( noCheckData.getCheckResAccount() + 1);
                    //同时也保存到消费记录表
                    List<ConsumerRecordTable> consumerRecordTables = consumerRecordDao.getByOtherIdAndSourceFrom( noCheckData.getId(), "MOONCARD_AUTO");
                    if( consumerRecordTables != null && consumerRecordTables.size() > 0){
                        for( ConsumerRecordTable consumerRecordTable : consumerRecordTables){
                            consumerRecordTable.setCheckResAccount( noCheckData.getCheckResAccount());
                            consumerRecordDao.save( consumerRecordTable);
                        }
                    }
                }
                mooncardDao.save( noCheckData);
            }
        }
    }

    /**
     *
     * @param description  Carte X9449 20/12 PHARMA LYONSTNIZIER LYON 1ER FRA
     * @return
     */
    private String handleDescription( String description){
        String key = description.split( " ")[3];;
        return key + description.split( key)[1];
    }

    /**
     * 计算员工的额度
     */
    public void handleDayMooncardLimit(){
        Double MAX_MONTH_LIMIT = 50000.00;//最大月额度
        Double MAX_DAY_LIMIT = 15000.00;//最大日额度
        List<AdminUserModel> users = userAdminService.findByBesideCode();
        for( AdminUserModel user : users){
            List<MooncardCardTable> cards = mooncardCardDao.findByAdminUserIdOrderByCreateTimeAsc( user.getId());
            if( cards == null || cards.size() == 0){
                continue;
            }
            //先只使用第一张卡吧
            MooncardCardTable mooncardCard = cards.get( 0);
            String bankCard = mooncardCard.getBankCardId();

            //计算该员工的可用余额
            Double validBalance = dataSummaryService.getValidBalance( user.getId());
            //30天内消费
            Double thirtyDayConsumer = dataSummaryService.getThirtyDayConsumer( user.getId());
            //昨天消费
            Double lastDayConsumer = dataSummaryService.getLastDayConsumer( user.getId());

            //月额度= 30天消费 + 可用余额
            Double monthLimit = thirtyDayConsumer + validBalance;
            if( monthLimit > MAX_MONTH_LIMIT){//不能超过最大月额度
                monthLimit = MAX_MONTH_LIMIT;
            }
            //周额度 = 月额度
            Double weeklyLimit = monthLimit.doubleValue();
            //日额度 = 昨日消费 + 可用余额
            Double dayLimit = lastDayConsumer + validBalance;
            if( dayLimit > MAX_DAY_LIMIT){//不能超过最大日额度
                dayLimit = MAX_DAY_LIMIT;
            }
            //将计算出的额度同步到mooncard平台
            mooncardConsumer.putCard( user.getId(), bankCard, monthLimit.intValue(), weeklyLimit.intValue(), dayLimit.intValue());
            //将计算出的额度保存到到数据库
            mooncardCard.setThresholdMonthly( monthLimit);
            mooncardCard.setThresholdWeekly( weeklyLimit);
            mooncardCard.setThresholdDaily( dayLimit);
            mooncardCard.setValidBalance( validBalance);
            mooncardCard.setUpdatedTime( new Date());
            mooncardCardDao.save( mooncardCard);
        }
    }

    /**
     *
     * @param filePath  excel的路径
     * @return  返回因为数据库重复而导入失败的数据
     * @throws CommonException
     * @throws FileNotFoundException
     */
    public JSONObject importFromExcel( String filePath) {
        //需要先将 excel的浏览器端访问路径 转化为服务器端访问路径
        filePath = FileUtils.transferClientFileUrl( filePath, baseClientDir, baseServerDir);

        File excelFile = new File( filePath);
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream( excelFile);
        } catch (FileNotFoundException e) {
            throw new CommonException( ErrorCodeDefine.INTERFACE_COMMON_ERROR, "找不到文件");
        }
        ExcelLogs logs = new ExcelLogs();
        List<ConsumerRecordModel> importExcelDatas = (List<ConsumerRecordModel>) ExcelUtil.importExcel( ConsumerRecordModel.class, inputStream, "", logs, 0);
        //过滤掉一些无效的行数据
        handleFilter( importExcelDatas);
        //过滤掉重复的数据
        List<ConsumerRecordModel> repeatDatas = handleRepeat( importExcelDatas);
        //批量设置修改/新增时间
        for( ConsumerRecordModel importExcelData : importExcelDatas){
            importExcelData.setCreateTime( new Date());
            importExcelData.setUpdateTime( new Date());
            importExcelData.setDateDeDebit( DateFormatUtil.format( importExcelData.getDateDeDebit(), DateFormatUtil.DATE_RULE_2));
            importExcelData.setDateDeDepense( DateFormatUtil.format( importExcelData.getDateDeDepense(), DateFormatUtil.DATE_RULE_2));
            AdminUserTable user = findByBankCard( importExcelData.getCarteIdentifiant());
            AssertUtil.assertNotNull(user, ErrorCodeDefine.BANK_CARD_NOT_EXSITS, "银行卡号[" + importExcelData.getCarteIdentifiant() + "]对应的员工不存在，导入失败");
            importExcelData.setImportUserId( user.getId());
            importExcelData.setSourceFrom( "MOONCARD_EXCEL");
        }
        mooncardDao.save( ModelUtils.copyListModel( importExcelDatas, MooncardTable.class));
        JSONObject json = new JSONObject();
        json.put( "repeatDatas", repeatDatas);
        json.put( "successCount", importExcelDatas.size());
        json.put( "errorDatas", logs.getErrorLogList());//返回错误的数据行
        return json;
    }

    public AdminUserTable findByBankCard( String bankNo){
        MooncardCardTable cardTable = mooncardCardDao.findByBankNo( bankNo);
        if( cardTable == null){
            return null;
        }
        return userAdminDao.findOne( cardTable.getAdminUserId());
    }

    /**
     * 把重复的数据筛选分离出来
     * @param importExcelDatas
     * @return
     */
    public List<ConsumerRecordModel> handleRepeat( List<ConsumerRecordModel> importExcelDatas) {
        List<ConsumerRecordModel> repeatDatas = new ArrayList<>();
        List<ConsumerRecordModel> cycleDatas = new ArrayList<>();
        cycleDatas.addAll( importExcelDatas);
        for( ConsumerRecordModel cycleData : cycleDatas){
            if(isRepeat( cycleData)){
                importExcelDatas.remove( cycleData);
                repeatDatas.add( cycleData);
            }
        }
        return repeatDatas;
    }

    /**
     * 把错误的数据筛选分离出来
     * @param importExcelDatas
     * @return
     */
    public void handleFilter( List<ConsumerRecordModel> importExcelDatas){
        List<ConsumerRecordModel> cycleDatas = new ArrayList<>();
        cycleDatas.addAll( importExcelDatas);
        for( ConsumerRecordModel cycleData : cycleDatas){
            //判断 MontantTTC和这两个最重要的列不能为空，才算是有效数据
            if( cycleData.getMontantTTC() == null || cycleData.getDateDeDepense() == null || !CustomerStringUtil.isNumber( cycleData.getMontantTTC())){
                importExcelDatas.remove( cycleData);
            }
        }
    }

    /**
     * 判断一条数据是否重复
     * 1、先判断今天只能导入今天之天的数据
     * 2、再判断数据库里面是否已经有要导入那天的数据，他们的导入是每天只会导入一次
     * 通过
     * @param model
     * @return 返回true代表有重复数据，返回false代表没有重复数据
     */
    private boolean isRepeat( ConsumerRecordModel model) {
        String dateDeDepense = model.getDateDeDepense();
        if( dateDeDepense == null){
            return false;
        }
        Date currDate = new Date( System.currentTimeMillis());
        //如果导入的交易日期 发生在今天 或者今天之后
        AssertUtil.assertFalse(DateFormatUtil.differentDays( currDate, new Date( dateDeDepense)) >= 0, ErrorCodeDefine.CONSUMER_IMPORT_REPEAT, "导入失败，只能导入今天(不包括今天)之前的消费记录");
        //判断这天的数据是否已经被导入
        List< MooncardTable> datas = mooncardDao.findByDateDeDepense( DateFormatUtil.format( dateDeDepense, DateFormatUtil.DATE_RULE_2));
        AssertUtil.assertFalse(datas != null && datas.size() != 0, ErrorCodeDefine.CONSUMER_IMPORT_REPEAT, "导入失败，今天的消费记录已经导入");
        return false;
    }

    // 总金额= 系统参数中mooncard初值 ＋ 确认到账的金额 －总消费的金额
    public Double getAccountTotal(){

        //查询系统参数里面的账户初始余额
        SystemparamTable systemparamTable = systemparamDao.getFirstByIdNotNull();
        Double mooncardBase = systemparamTable.getMooncardBaseCount() == null ? 0d : systemparamTable.getMooncardBaseCount();
        //总消费额
        Double totalConsumer = Math.abs( consumerRecordDao.sum());
        //确认到账的金额
        Double recharge = Math.abs( rechargeRecordDao.sumByMoneyStatus());

        BigDecimal total = new BigDecimal( mooncardBase).add( new BigDecimal( recharge)).subtract( new BigDecimal( totalConsumer));
        DecimalFormat df = new DecimalFormat("#.00");
        return Double.valueOf( df.format( total));
    }
}
